home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / sync / syncLock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  25.0 KB  |  945 lines

  1. /* 
  2.  * syncLock.c --
  3.  *
  4.  *    These are internal locking routines of the Synchronization module.
  5.  *    These routines are slower but safer versions of the routines (found
  6.  *    in sync.h) to get and release monitor locks, and to wait on
  7.  *    and notify condition variables.
  8.  *
  9.  *    A process is blocked by making it wait on an event.  An event is
  10.  *    just an uninterpreted integer that gets 'signaled' by the routine
  11.  *    Sync_SlowBroadcast.
  12.  *
  13.  * Copyright 1985 Regents of the University of California
  14.  * All rights reserved.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/sync/syncLock.c,v 9.13 92/01/06 15:19:49 kupfer Exp $ SPRITE (Berkeley)";
  19. #endif /* not lint */
  20.  
  21. #include <sync.h>
  22. #include <sprite.h>
  23. #include <mach.h>
  24. #include <list.h>
  25. #include <syncInt.h>
  26. #include <sched.h>
  27. #include <proc.h>
  28. #include <timer.h>
  29. #include <rpc.h>
  30. #include <bstring.h>
  31.  
  32. /*
  33.  * A counter to record the number of busy wait loops executed
  34.  * while trying to P a semaphore.  This is incremented inside the
  35.  * loop of MASTER_LOCK.
  36.  */
  37. int sync_BusyWaits = 0;
  38.  
  39. /*
  40.  * A counter to record the number of events that had clashes on the hash.
  41.  */
  42.  
  43. int    sync_Collisions = 0;
  44.  
  45. /*
  46.  * The event hash chain.  Process control blocks are placed in a hash
  47.  * chain keyed on the event that the process is waiting on.
  48.  */
  49.  
  50. #define PROC_HASHBUCKETS    63
  51. static List_Links eventChainHeaders[PROC_HASHBUCKETS];
  52.  
  53. /*
  54.  * Instrumentation to record the number of calls to the wakeup routine
  55.  * and to record how many processes were woken up.
  56.  */
  57.  
  58. Sync_Instrument sync_Instrument[MACH_MAX_NUM_PROCESSORS];
  59. Sync_Instrument *sync_InstrumentPtr[MACH_MAX_NUM_PROCESSORS];
  60.  
  61. /*
  62.  * Statistics related to remote waiting.
  63.  */
  64. int syncProcWakeupRaces = 0;
  65.  
  66. static void ProcessWakeup _ARGS_((Proc_ControlBlock *procPtr, int waitToken));
  67.  
  68.  
  69. /*
  70.  *----------------------------------------------------------------------------
  71.  *
  72.  * Sync_Init --
  73.  *
  74.  *    This initializes the event hash chain.  The hash table is
  75.  *    an array of list headers.
  76.  *
  77.  *    Instrumentation variables are also initialized.
  78.  *
  79.  * Results:
  80.  *     None.
  81.  *
  82.  * Side effects:
  83.  *    The hash chain headers are initialized to be dummy list elements
  84.  *
  85.  *----------------------------------------------------------------------------
  86.  */
  87. void
  88. Sync_Init()
  89. {
  90.     register int i;
  91.  
  92.     for (i=0 ; i<PROC_HASHBUCKETS ; i++) {
  93.     List_Init(&eventChainHeaders[i]);
  94.     }
  95.     bzero((Address) sync_Instrument, sizeof(sync_Instrument));
  96.     for (i=0; i < MACH_MAX_NUM_PROCESSORS; i++) {
  97.     sync_InstrumentPtr[i] = &sync_Instrument[i];
  98.     }
  99. }
  100.  
  101.  
  102. /*
  103.  *----------------------------------------------------------------------
  104.  *
  105.  * Sync_GetLock --
  106.  *
  107.  *    This is the kernel version of the Sync_GetLock routine. The user
  108.  *     version is written in assembler, but in the kernel we want to
  109.  *    record locking statistics so we have our own version.
  110.  *
  111.  * Results:
  112.  *    None.
  113.  *
  114.  * Side effects:
  115.  *    The type of the previous lock is added to the array of prior types.
  116.  *    The lock is added to the lock stack in the pcb.
  117.  *
  118.  *----------------------------------------------------------------------
  119.  */
  120.  
  121. ReturnStatus
  122. Sync_GetLock(lockPtr)
  123.    Sync_Lock *lockPtr;
  124. {
  125.     ReturnStatus    status = SUCCESS;
  126.  
  127.     Sync_LockRegister(lockPtr);
  128.     if (Mach_TestAndSet(&(lockPtr->inUse)) != 0) {
  129.     status = Sync_SlowLock(lockPtr); 
  130.     } else {
  131.     Sync_RecordHit(lockPtr);
  132.     Sync_StoreDbgInfo(lockPtr, FALSE);
  133.     Sync_AddPrior(lockPtr);
  134.     }
  135.     return status;
  136. }
  137.  
  138.  
  139. /*
  140.  *----------------------------------------------------------------------
  141.  *
  142.  *  Sync_Unlock--
  143.  *
  144.  *    The kernel version of the unlock routine. We have a different
  145.  *    version from the user so we can do locking statistics.
  146.  *
  147.  * Results:
  148.  *    None.
  149.  *
  150.  * Side effects:
  151.  *    The lock is removed from the lock stack in the pcb.
  152.  *
  153.  *----------------------------------------------------------------------
  154.  */
  155.  
  156. ReturnStatus
  157. Sync_Unlock(lockPtr)
  158.     Sync_Lock *lockPtr;
  159. {
  160.     ReturnStatus    status = SUCCESS;
  161.  
  162.     lockPtr->inUse = 0;
  163.     SyncDeleteCurrent(lockPtr);
  164.     if (lockPtr->waiting) {
  165.     status = Sync_SlowBroadcast((unsigned int)lockPtr, &lockPtr->waiting);
  166.     }
  167.     return status;
  168. }
  169.  
  170.  
  171. /*
  172.  *----------------------------------------------------------------------------
  173.  *
  174.  * Sync_SlowLock --
  175.  *
  176.  *    Acquire a lock while holding the synchronization master lock.
  177.  *
  178.  *      Inside the critical section the inUse bit is checked.  If we have
  179.  *      to wait the process is put to sleep waiting on an event associated
  180.  *      with the lock.
  181.  *
  182.  * Results:
  183.  *    SUCCESS        is always returned.
  184.  *
  185.  * Side effects:
  186.  *      The lock is acquired when this procedure returns.  The process may
  187.  *      have been put to sleep while waiting for the lock to become
  188.  *      available.
  189.  *
  190.  *----------------------------------------------------------------------------
  191.  */
  192.  
  193. ENTRY ReturnStatus
  194. Sync_SlowLock(lockPtr)
  195.     register    Sync_Lock    *lockPtr;
  196. {
  197.     MASTER_LOCK(sched_MutexPtr);
  198.  
  199. #ifdef spur
  200.     Mach_InstCountStart(0);
  201. #endif
  202.  
  203.     while (Mach_TestAndSet(&(lockPtr->inUse)) != 0) {
  204.     lockPtr->waiting = TRUE;
  205.     /*
  206.      * Check the inUse semaphore again after setting the waiting. A zero 
  207.      * semaphore value means the lock was released after our previous
  208.      * TestAndSet and possibly before we set the waiting flag. This test
  209.      * prevents us from waiting if the Sync_Lock missed our waiting flag.
  210.      */
  211.         if (Mach_TestAndSet(&(lockPtr->inUse)) == 0) {
  212.         break;
  213.     }
  214.     (void) SyncEventWaitInt((unsigned int)lockPtr, FALSE);
  215.     Sync_RecordMiss(lockPtr);
  216. #ifdef spur
  217.     Mach_InstCountEnd(1);
  218. #endif
  219.     MASTER_UNLOCK(sched_MutexPtr);
  220.     MASTER_LOCK(sched_MutexPtr);
  221. #ifdef spur
  222.     Mach_InstCountStart(0);
  223. #endif
  224.     }
  225.     Sync_RecordHit(lockPtr);
  226.     Sync_StoreDbgInfo(lockPtr, FALSE);
  227.     Sync_AddPrior(lockPtr);
  228. #ifdef spur
  229.     Mach_InstCountOff(0);
  230.     if (Mach_InstCountIsOn(1)) {
  231.     panic("About to unlock sched_Mutex with inst count on.\n");
  232.     }
  233. #endif
  234.     MASTER_UNLOCK(sched_MutexPtr);
  235.     return(SUCCESS);
  236. }
  237.  
  238.  
  239. /*
  240.  *----------------------------------------------------------------------------
  241.  *
  242.  * Sync_SlowWait --
  243.  *
  244.  *      Wait on a condition.  The lock is released and the process is blocked
  245.  *      on the event.  A future call to SyncSlowBroadcast will signal the
  246.  *      condition and make this process runnable again.  Before returning
  247.  *    the lock is reaquired.
  248.  *
  249.  *      This can only be called while a lock is held.  This forces our
  250.  *      client to safely check global state while in a monitor.
  251.  *
  252.  * Results:
  253.  *    TRUE if interrupted because of signal, FALSE otherwise.
  254.  *
  255.  * Side effects:
  256.  *      Put the process to sleep and release the monitor lock.  Other
  257.  *      processes waiting on the monitor lock become runnable.
  258.  *
  259.  *----------------------------------------------------------------------------
  260.  */
  261.  
  262. ENTRY Boolean
  263. Sync_SlowWait(conditionPtr, lockPtr, wakeIfSignal)
  264.     Sync_Condition    *conditionPtr;    /* Condition to wait on. */
  265.     register Sync_Lock     *lockPtr;    /* Lock to release. */
  266.     Boolean        wakeIfSignal;    /* TRUE => wake if signal pending. */
  267. {
  268.     Boolean    sigPending;
  269.  
  270.     conditionPtr->waiting = TRUE;
  271.     MASTER_LOCK(sched_MutexPtr);
  272.     /*
  273.      * release the monitor lock and wait on the condition
  274.      */
  275.     lockPtr->inUse = 0;
  276.     lockPtr->waiting = FALSE;
  277.     SyncDeleteCurrent(lockPtr);
  278.     SyncEventWakeupInt((unsigned int)lockPtr);
  279.     sigPending = SyncEventWaitInt((unsigned int) conditionPtr, wakeIfSignal);
  280. #ifdef spur
  281.     Mach_InstCountEnd(1);
  282. #endif
  283.     MASTER_UNLOCK(sched_MutexPtr);
  284.  
  285.     (void) Sync_GetLock(lockPtr);
  286.  
  287.     return(sigPending);
  288. }
  289.  
  290.  
  291. /*
  292.  *----------------------------------------------------------------------------
  293.  *
  294.  * Sync_SlowBroadcast --
  295.  *
  296.  *      Mark all processes waiting on an event as runable.  The flag that
  297.  *      indicates there are waiters is cleared here inside the protected
  298.  *      critical section.  This has "broadcast" semantics because everyone
  299.  *      waiting is made runable.  We don't yet have a mechanism to wake up
  300.  *      just one waiting process.
  301.  *
  302.  * Results:
  303.  *    SUCCESS        is always returned.
  304.  *
  305.  * Side effects:
  306.  *    Make processes waiting on the event runnable.
  307.  *
  308.  *----------------------------------------------------------------------------
  309.  */
  310.  
  311. ENTRY ReturnStatus
  312. Sync_SlowBroadcast(event, waitFlagPtr)
  313.     unsigned int event;
  314.     int *waitFlagPtr;
  315. {
  316.     MASTER_LOCK(sched_MutexPtr);
  317.  
  318.     *waitFlagPtr = FALSE;
  319.     SyncEventWakeupInt(event);
  320. #ifdef spur
  321.     if (Mach_InstCountIsOn(1)) {
  322.     panic("About to unlock sched_Mutex with inst count on.\n");
  323.     }
  324. #endif
  325.  
  326.     MASTER_UNLOCK(sched_MutexPtr);
  327.     return(SUCCESS);
  328. }
  329.  
  330.  
  331. /*
  332.  *----------------------------------------------------------------------------
  333.  *
  334.  * Sync_SlowMasterWait --
  335.  *
  336.  *      Wait on an event.  Like SyncSlowWait except that the lock that
  337.  *    is released is a master lock, not a monitor lock.
  338.  *
  339.  * Results:
  340.  *    TRUE if wake up because of a signal, FALSE otherwise.
  341.  *
  342.  * Side effects:
  343.  *      Put the process to sleep and release the master lock.  Other
  344.  *      processes waiting on the monitor lock become runnable.
  345.  *    
  346.  *
  347.  *----------------------------------------------------------------------------
  348.  */
  349.  
  350. ENTRY Boolean
  351. Sync_SlowMasterWait(event, mutexPtr, wakeIfSignal)
  352.     unsigned int     event;        /* Event to wait on. */
  353.     Sync_Semaphore    *mutexPtr;    /* Mutex to release and reaquire. */
  354.     Boolean         wakeIfSignal;    /* TRUE => wake if signal pending. */
  355. {
  356.     Boolean    sigPending;
  357.  
  358.     MASTER_LOCK(sched_MutexPtr);
  359.  
  360.     /*
  361.      * release the master lock and wait on the condition
  362.      */
  363.     MASTER_UNLOCK(mutexPtr);
  364.  
  365.     sigPending = SyncEventWaitInt(event, wakeIfSignal);
  366.  
  367. #ifdef spur
  368.     Mach_InstCountEnd(1);
  369. #endif
  370.  
  371.     MASTER_UNLOCK(sched_MutexPtr);
  372.     /*
  373.      * re-acquire master lock before proceeding
  374.      */
  375.     MASTER_LOCK(mutexPtr);
  376.  
  377.     return(sigPending);
  378. }
  379.  
  380.  
  381. /*
  382.  *----------------------------------------------------------------------------
  383.  *
  384.  * Sync_UnlockAndSwitch --
  385.  *
  386.  *      Release the monitor lock and then perform a context switch to the
  387.  *    given state.
  388.  *
  389.  * Results:
  390.  *    SUCCESS        is always returned.
  391.  *
  392.  * Side effects:
  393.  *      Context switch the process and release the monitor lock.  Other
  394.  *      processes waiting on the monitor lock become runnable.
  395.  *    
  396.  *----------------------------------------------------------------------------
  397.  */
  398.  
  399. void
  400. Sync_UnlockAndSwitch(lockPtr, state)
  401.     register    Sync_Lock     *lockPtr;
  402.     Proc_State            state;
  403. {
  404.  
  405.     MASTER_LOCK(sched_MutexPtr);
  406.     /*
  407.      * release the monitor lock and context switch.
  408.      */
  409.     lockPtr->inUse = 0;
  410.     lockPtr->waiting = FALSE;
  411.     SyncDeleteCurrent(lockPtr);
  412.     SyncEventWakeupInt((unsigned int)lockPtr);
  413.     Sched_ContextSwitchInt(state);
  414. #ifdef spur
  415.     Mach_InstCountEnd(1);
  416. #endif
  417.     MASTER_UNLOCK(sched_MutexPtr);
  418. }
  419.  
  420.  
  421. /*
  422.  *----------------------------------------------------------------------------
  423.  *
  424.  * SyncEventWakeupInt --
  425.  *
  426.  *      This looks through the process table for processes waiting on an
  427.  *      event.  For each one it finds it clears its event and marks the
  428.  *      process runnable.  Blocked processes are placed on a hash chain
  429.  *    keyed on the event they are blocked on.  It is this hash chain
  430.  *    that this procedure scans.
  431.  *
  432.  * Results:
  433.  *    None.
  434.  *
  435.  * Side effects:
  436.  *      removes process table entries from their event hash chain and
  437.  *      marks them runnable.
  438.  *
  439.  *----------------------------------------------------------------------------
  440.  */
  441.  
  442. INTERNAL void
  443. SyncEventWakeupInt(event)
  444.     unsigned int event;
  445. {
  446.     register    Proc_ControlBlock     *procPtr;
  447.     register    Proc_PCBLink         *hashChainItemPtr;
  448.     register    List_Links         *chainHeader;
  449.     register    List_Links        *itemPtr;
  450.     int        pnum;
  451.  
  452.     if (!sched_MutexPtr->value) {
  453.     panic("SyncEventWakeupInt: master lock not held.\n");
  454.     }
  455.     pnum = Mach_GetProcessorNumber();
  456.     
  457.     sync_Instrument[pnum].numWakeupCalls++;
  458.     chainHeader = &eventChainHeaders[event % PROC_HASHBUCKETS];
  459.  
  460.     itemPtr = List_First(chainHeader);
  461.     while (!List_IsAtEnd(chainHeader, itemPtr)) {
  462.     hashChainItemPtr = (Proc_PCBLink *)itemPtr;
  463.     itemPtr = List_Next(itemPtr);
  464.     procPtr = hashChainItemPtr->procPtr;
  465.     if (procPtr->event != event) {
  466.         sync_Collisions++;
  467.         continue;
  468.     }
  469.     switch (procPtr->state) {
  470.         case PROC_WAITING:
  471.             break;
  472.         case PROC_MIGRATED:
  473.         /*
  474.          * Need to handle waking up migrated processes.
  475.          */
  476.         panic("Can't handle waking up a migrated proc.\n");
  477.         break;
  478.         default:
  479.         panic("%s %s",  
  480.               "Sync_EventWakeupInt:",
  481.               "Tried to wakeup a non-waiting proc.\n");
  482.         break;
  483.  
  484.     }
  485.  
  486.     sync_Instrument[pnum].numWakeups++;
  487.     List_Remove((List_Links *) hashChainItemPtr);
  488.     procPtr->event = NIL;
  489.     if (procPtr->state == PROC_WAITING) {
  490.         procPtr->state = PROC_READY;
  491.         Sched_InsertInQueue(procPtr, (Proc_ControlBlock **) NIL);
  492.     }
  493.     }
  494. }
  495.  
  496.  
  497. /*
  498.  *----------------------------------------------------------------------------
  499.  *
  500.  * Sync_WakeWaitingProcess --
  501.  *
  502.  *      Wake up a particular process as though the local or remote event it is 
  503.  *    awaiting has occurred.
  504.  *
  505.  *    This code was originally written for a uniprocessor. As a result, the
  506.  *    case of signaling a running process was never dealt with. We must
  507.  *    prevent a running process from going to sleep in between the time
  508.  *    we see it is running, and the time it gets the signal. It would seem
  509.  *    we could do this by locking the pcb, but unfortunately 
  510.  *    Sync_EventWaitInt does not grab this lock. This means we have to grab
  511.  *    the sched_MutexPtr. Ideally we would grab the mutex in the sig module
  512.  *    (Sig_Send perhaps). If we did that, then we would deadlock in this
  513.  *    routine. The bottom line is that this routine must do more than its
  514.  *    name implies, due to some weirdness in the way the system is
  515.  *    structured. If a process is ready, nothing is done. If a process
  516.  *    is running, the other processor is interrupted to force it into the
  517.  *    kernel, at which point it sees the signal.
  518.  *
  519.  * Results:
  520.  *    None.
  521.  *
  522.  * Side effects:
  523.  *      If waiting on an event, removes the given process from its event hash 
  524.  *    chain and makes it runnable. If running, interrupts other processor.
  525.  *
  526.  *----------------------------------------------------------------------------
  527.  */
  528.  
  529. void
  530. Sync_WakeWaitingProcess(procPtr)
  531.     register    Proc_ControlBlock     *procPtr;
  532. {
  533.     MASTER_LOCK(sched_MutexPtr);
  534.     if (procPtr->event != NIL) {
  535.     List_Remove(&procPtr->eventHashChain.links);
  536.     procPtr->event = NIL;
  537.     procPtr->state = PROC_READY;
  538.     Sched_InsertInQueue(procPtr, (Proc_ControlBlock **) NIL);
  539.     } else if (procPtr->state == PROC_WAITING) {
  540.         if (!(procPtr->syncFlags & SYNC_WAIT_REMOTE)) {
  541.         panic("Sync_WakeWaitingProcess: Proc waiting but event and remote wait NIL\n");
  542.         }
  543.         ProcessWakeup(procPtr, procPtr->waitToken);
  544.     } else if (procPtr->state == PROC_RUNNING &&
  545.            procPtr->processor != Mach_GetProcessorNumber()) {
  546.     Mach_CheckSpecialHandling(procPtr->processor);
  547.     }
  548. #ifdef spur
  549.     if (Mach_InstCountIsOn(1)) {
  550.     panic("About to unlock sched_Mutex with inst count on.\n");
  551.     }
  552. #endif
  553.     MASTER_UNLOCK(sched_MutexPtr);
  554. }
  555.  
  556.  
  557. /*
  558.  *----------------------------------------------------------------------------
  559.  *
  560.  * Sync_RemoveWaiter --
  561.  *
  562.  *      Remove a process from any event chain it may be on.
  563.  *    This is distinguished from Sync_WakeWaitingProcess because
  564.  *    it does not place the process in the ready queue.
  565.  *
  566.  * Results:
  567.  *    None.
  568.  *
  569.  * Side effects:
  570.  *    None.
  571.  *
  572.  *----------------------------------------------------------------------------
  573.  */
  574.  
  575. void
  576. Sync_RemoveWaiter(procPtr)
  577.     register    Proc_ControlBlock     *procPtr;
  578. {
  579.     MASTER_LOCK(sched_MutexPtr);
  580.     if (procPtr->event != NIL) {
  581.     List_Remove(&procPtr->eventHashChain.links);
  582.     procPtr->event = NIL;
  583.     } else {
  584.     if (procPtr->state == PROC_WAITING) {
  585.         if (!(procPtr->syncFlags & SYNC_WAIT_REMOTE)) {
  586.         panic("Sync_RemoveWaiter: Proc waiting but event and remote wait NIL\n");
  587.         }
  588.         procPtr->syncFlags |= SYNC_WAIT_COMPLETE;
  589.     }
  590.     }
  591.     MASTER_UNLOCK(sched_MutexPtr);
  592. }
  593.  
  594.  
  595. /*
  596.  *----------------------------------------------------------------------------
  597.  *
  598.  * SyncEventWaitInt --
  599.  *
  600.  *    Make a process sleep waiting for an event.  The blocked process is
  601.  *    placed on a hash chain keyed on the event.  This routine will return
  602.  *    without putting the process to sleep if there is a signal pending
  603.  *    and the proper flag is set in the proc table.
  604.  *
  605.  * Results:
  606.  *    TRUE if woke up because of a signal, FALSE otherwise.
  607.  *
  608.  * Side effects:
  609.  *    The event that the process is waiting for is noted in the process
  610.  *    table.  The process is marked as waiting and a new process
  611.  *    is selected to run.
  612.  *
  613.  *----------------------------------------------------------------------------
  614.  */
  615.  
  616. INTERNAL Boolean
  617. SyncEventWaitInt(event, wakeIfSignal)
  618.     unsigned     int     event;        /* Event to wait on. */
  619.     Boolean        wakeIfSignal;    /* TRUE => wake if signal. */
  620. {
  621.     Proc_ControlBlock *procPtr;
  622.     List_Links *chainHeader;
  623.  
  624.     procPtr = Proc_GetCurrentProc();
  625.  
  626.     if (wakeIfSignal && Sig_Pending(procPtr)) {
  627.     return(TRUE);
  628.     }
  629.  
  630.     chainHeader = &eventChainHeaders[event % PROC_HASHBUCKETS];
  631.     List_Insert(&procPtr->eventHashChain.links, LIST_ATREAR(chainHeader));
  632.  
  633.     procPtr->event = event;
  634.     Sched_ContextSwitchInt(PROC_WAITING);
  635.     return(FALSE);
  636. }
  637.  
  638.  
  639. /*
  640.  *----------------------------------------------------------------------------
  641.  *
  642.  * Sync_GetWaitToken --
  643.  *
  644.  *    Return the process id and increment and return wait token for the 
  645.  *    current process.
  646.  *
  647.  * Results:
  648.  *    process ID and wait token for current process.
  649.  *
  650.  * Side effects:
  651.  *    Wait token incremented.
  652.  *
  653.  *----------------------------------------------------------------------------
  654.  */
  655.  
  656. ENTRY void
  657. Sync_GetWaitToken(pidPtr, tokenPtr)
  658.     Proc_PID    *pidPtr;    /* If non-nil pid of current process. */
  659.     int        *tokenPtr;    /* Wait token of current process. */
  660. {
  661.     register    Proc_ControlBlock    *procPtr;
  662.  
  663.     procPtr = Proc_GetCurrentProc();
  664.  
  665.     MASTER_LOCK(sched_MutexPtr);
  666.  
  667.     procPtr->waitToken++;
  668.     if (pidPtr != (Proc_PID *) NIL) {
  669.     *pidPtr = procPtr->processID;
  670.     }
  671.     *tokenPtr = procPtr->waitToken;
  672.  
  673.     MASTER_UNLOCK(sched_MutexPtr);
  674. }
  675.  
  676.  
  677. /*
  678.  *----------------------------------------------------------------------------
  679.  *
  680.  * Sync_SetWaitToken --
  681.  *
  682.  *    Set the wait token for the given process.  Only exists for process
  683.  *    migration should not be used in general.
  684.  *
  685.  * Results:
  686.  *    None.
  687.  *
  688.  * Side effects:
  689.  *    Wait token value set in the PCB for the given process.
  690.  *
  691.  *----------------------------------------------------------------------------
  692.  */
  693.  
  694. ENTRY void
  695. Sync_SetWaitToken(procPtr, waitToken)
  696.     Proc_ControlBlock    *procPtr;    /* Process to set token for. */
  697.     int            waitToken;    /* Token value. */
  698. {
  699.     MASTER_LOCK(sched_MutexPtr);
  700.  
  701.     procPtr->waitToken = waitToken;
  702.  
  703.     MASTER_UNLOCK(sched_MutexPtr);
  704. }
  705.  
  706.  
  707. /*
  708.  *----------------------------------------------------------------------------
  709.  *
  710.  * Sync_ProcWait --
  711.  *
  712.  *    This is called to block a process after it has been told by a
  713.  *    remote host that it has to wait.  The wait completed flag is
  714.  *    checked here to see if the remote host's wakeup message has raced 
  715.  *    (and won) with this process's decision to call this procedure.
  716.  *
  717.  *    For safety, this routine should be expanded to automatically
  718.  *    set up a timeout event which will wake up the process anyway.
  719.  *
  720.  * Results:
  721.  *    TRUE if woke up because of a signal, FALSE otherwise.
  722.  *
  723.  * Side effects:
  724.  *    The wait complete flag of the process is checked and the process
  725.  *    is blocked if a notify message has not already arrived.
  726.  *
  727.  *----------------------------------------------------------------------------
  728.  */
  729.  
  730. ENTRY Boolean
  731. Sync_ProcWait(lockPtr, wakeIfSignal)
  732.     Sync_Lock    *lockPtr;    /* If non-nil release this lock before going to
  733.                  * sleep and reaquire it after waking up. */
  734.     Boolean    wakeIfSignal;    /* TRUE => Don't go to sleep if a signal is
  735.                  *         pending. */
  736. {
  737.     register    Proc_ControlBlock     *procPtr;
  738.     Boolean                releasedLock = FALSE;
  739.     Boolean                sigPending = FALSE;
  740.  
  741.     MASTER_LOCK(sched_MutexPtr);
  742.     procPtr = Proc_GetCurrentProc();
  743.     if (!(procPtr->syncFlags & SYNC_WAIT_COMPLETE)) {
  744.     if (wakeIfSignal && Sig_Pending(procPtr)) {
  745.         /*
  746.          * Check for signals.   If a signal is pending, then bail out.
  747.          */
  748.         sigPending = TRUE;
  749.     } else {
  750.         /*
  751.          * Block the process.  The wakeup message from the remote host
  752.          * has not arrived.
  753.          */
  754.         procPtr->syncFlags |= SYNC_WAIT_REMOTE;
  755.         if (lockPtr != (Sync_Lock *) NIL) {
  756.         /*
  757.          * We were given a monitor lock to release, so release it.
  758.          */
  759.         lockPtr->inUse = 0;
  760.         lockPtr->waiting = FALSE;
  761.         SyncEventWakeupInt((unsigned int)lockPtr);
  762.         releasedLock = TRUE;
  763.         }
  764.         Sched_ContextSwitchInt(PROC_WAITING);
  765.         if (wakeIfSignal && Sig_Pending(procPtr)) {
  766.         sigPending = TRUE;
  767.         }
  768.     }
  769.     }
  770.     /*
  771.      * After being notified (and context switching back to existence),
  772.      * or if we have already been notified, clear state about the
  773.      * remote wait.  This means our caller should get a new token
  774.      * (ie. retry whatever remote operation it was) before waiting
  775.      * again.
  776.      */
  777.     procPtr->waitToken++;
  778.     procPtr->syncFlags &= ~(SYNC_WAIT_COMPLETE | SYNC_WAIT_REMOTE);
  779. #ifdef spur
  780.     Mach_InstCountEnd(1);
  781. #endif
  782.     MASTER_UNLOCK(sched_MutexPtr);
  783.     if (releasedLock) {
  784.     (void) Sync_GetLock(lockPtr);
  785.     }
  786.     return(sigPending);
  787. }
  788.  
  789.  
  790. /*
  791.  *----------------------------------------------------------------------------
  792.  *
  793.  * Sync_ProcWakeup --
  794.  *
  795.  *    Wakeup a blocked process in response to a message from a remote
  796.  *    host.  Call internal routine to do the work.
  797.  *
  798.  * Results:
  799.  *    None.
  800.  *
  801.  * Side effects:
  802.  *    None.
  803.  *
  804.  *----------------------------------------------------------------------------
  805.  */
  806.  
  807. ENTRY void
  808. Sync_ProcWakeup(pid, token)
  809.     Proc_PID     pid;    /* PID of process to wake up. */
  810.     int        token;    /* Token to use to wake up process. */
  811. {
  812.     Proc_ControlBlock     *procPtr;
  813.  
  814.     procPtr = Proc_GetPCB(pid);
  815.     if (procPtr != (Proc_ControlBlock *)NIL) {
  816.     MASTER_LOCK(sched_MutexPtr);
  817.     ProcessWakeup(procPtr, token);
  818.     MASTER_UNLOCK(sched_MutexPtr);
  819.     }
  820. }
  821.  
  822.  
  823. /*
  824.  *----------------------------------------------------------------------------
  825.  *
  826.  * ProcessWakeup --
  827.  *
  828.  *    Wakeup a blocked process in response to a message from a remote
  829.  *    host.  It is possible that the wakeup message has raced and
  830.  *    won against the local process's call to Sync_ProcWait.  This
  831.  *    protected against with a token and a wakeup complete flag.
  832.  *    (The token provides extra protection against spurious wakeups.
  833.  *     As we don't make any guarantees about the correctness of a
  834.  *     wakeup anyway, we ignore the token here.)
  835.  *
  836.  * Results:
  837.  *    None.
  838.  *
  839.  * Side effects:
  840.  *    syncFlags modified.
  841.  *
  842.  *----------------------------------------------------------------------------
  843.  */
  844.  
  845. /* ARGSUSED */
  846. static INTERNAL void
  847. ProcessWakeup(procPtr, waitToken)
  848.     register    Proc_ControlBlock     *procPtr;    /* Process to wake up.*/
  849.     int                    waitToken;    /* Token to use. Now
  850.                              * this is ignored. */
  851. {
  852.     procPtr->syncFlags |= SYNC_WAIT_COMPLETE;
  853.     if (procPtr->state == PROC_WAITING) {
  854.     /*
  855.      * Only wakeup if are doing a 'process wait' and not an 'event wait'.
  856.      */
  857.     if (procPtr->event == NIL) {
  858.         procPtr->state = PROC_READY;
  859.         Sched_InsertInQueue(procPtr, (Proc_ControlBlock **) NIL);
  860.     }
  861.     } else {
  862.     /*
  863.      * This is a notify message which has raced (and won) with the 
  864.      * process's call to Sync_ProcWait.
  865.      */
  866.     syncProcWakeupRaces++;
  867.     }
  868. }
  869.  
  870.  
  871. /*
  872.  *----------------------------------------------------------------------
  873.  *
  874.  * Sync_RemoteNotify --
  875.  *
  876.  *    Perform an RPC to notify a remote process.
  877.  *
  878.  * Results:
  879.  *    The return code from the RPC.  This enables the caller to decide
  880.  *    if it should wait and retry the notify later if the remote
  881.  *    host is unavailable.
  882.  *
  883.  * Side effects:
  884.  *      This results in a call to Sync_ProcWakeup on the host of the
  885.  *      waiting process.
  886.  *
  887.  *----------------------------------------------------------------------
  888.  */
  889. ReturnStatus
  890. Sync_RemoteNotify(waitPtr)
  891.     Sync_RemoteWaiter *waitPtr;        /* Arguments to remote notify. */
  892. {
  893.     Rpc_Storage storage;
  894.     ReturnStatus status;
  895.  
  896.     storage.requestParamPtr = (Address)waitPtr;
  897.     storage.requestParamSize = sizeof(Sync_RemoteWaiter);
  898.     storage.requestDataSize = 0;
  899.     storage.replyParamSize = 0;
  900.     storage.replyDataSize = 0;
  901.     status = Rpc_Call(waitPtr->hostID, RPC_REMOTE_WAKEUP, &storage);
  902.     return(status);
  903. }
  904.  
  905.  
  906. /*
  907.  *----------------------------------------------------------------------
  908.  *
  909.  * Sync_RemoteNotifyStub --
  910.  *
  911.  *    The service stub for the remote wakeup RPC.
  912.  *
  913.  * Results:
  914.  *    SUCCESS.
  915.  *
  916.  * Side effects:
  917.  *      A call to Sync_ProcWakeup on the process.
  918.  *
  919.  *----------------------------------------------------------------------
  920.  */
  921.  
  922. /* ARGSUSED */
  923. ReturnStatus
  924. Sync_RemoteNotifyStub(srvToken, clientID, command, storagePtr)
  925.     ClientData     srvToken;    /* Handle on server process passed to
  926.                  * Rpc_Reply. */
  927.     int     clientID;    /* Sprite ID of client host (ignored). */
  928.     int     command;    /* Command identifier (ignored). */
  929.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  930.                  * buffers and also indicate the exact amount
  931.                  * of data in the request buffers.  The reply
  932.                  * fields are initialized to NIL for the
  933.                  * pointers and 0 for the lengths.  This can
  934.                  * be passed to Rpc_Reply. */
  935. {
  936.     register Sync_RemoteWaiter *waitPtr;
  937.  
  938.     waitPtr = (Sync_RemoteWaiter *)storagePtr->requestParamPtr;
  939.     Sync_ProcWakeup(waitPtr->pid, waitPtr->waitToken);
  940.     Rpc_Reply(srvToken, SUCCESS, storagePtr, (int (*) ()) NIL,
  941.           (ClientData) NIL);
  942.     return(SUCCESS);
  943. }
  944.  
  945.